﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web;

namespace Dashboard.Hubs
{
    public class HealthStatusView
    {
        public double FreeRam { get; set; }
        public double UsedRam { get; set; }
        public int DiskUsage { get; set; }
        public int CpuUsage { get; set; }
        public double FreeHDD { get; set; }
        public double UsedHDD { get; set; }
    }

    public class AveragedHealthStatusView
    {
        public double TotalRam { get; set; }
        public double UsedRam { get; set; }
        public double DiskUsage { get; set; }
        public double CpuUsage { get; set; }
    }

    public class HealthMonitor
    {
        private static HealthMonitor instance;

        Microsoft.VisualBasic.Devices.ComputerInfo computerInfo;
        PerformanceCounter cpuCounter;
        PerformanceCounter diskIdleCounter;
        DriveInfo cDrive;

        public static int Step
        {
            get
            {
                return 100;
            }
            private set { }
        }

        private HealthMonitor()
        {
            computerInfo = new Microsoft.VisualBasic.Devices.ComputerInfo();

            cpuCounter = new PerformanceCounter(
                "Processor",
                "% Processor Time",
                "_Total");

            var perfCategory = new PerformanceCounterCategory("PhysicalDisk");
            string[] instanceNames = perfCategory.GetInstanceNames();

            string driveName = string.Empty;
            foreach (string name in instanceNames)
            {
                if (name.IndexOf("C:") > 0)
                {
                    if (string.IsNullOrEmpty(driveName))
                        driveName = name;
                }
            }

            diskIdleCounter = new PerformanceCounter(
                "PhysicalDisk",
                "% Idle Time",
                driveName);

            cDrive = new DriveInfo("C");
        }

        static HealthMonitor()
        {
            instance = new HealthMonitor();
        }

        private HealthStatusView GetHealthStatus()
        {
            var result = new HealthStatusView()
            {
                UsedRam = (computerInfo.TotalPhysicalMemory - computerInfo.AvailablePhysicalMemory) / 1024 / 1024,
                FreeRam = computerInfo.AvailablePhysicalMemory / 1024 / 1024,
                DiskUsage = 100 - (int)diskIdleCounter.NextValue(),
                CpuUsage = (int)cpuCounter.NextValue()
            };

            if (cDrive.IsReady)
            {
                result.FreeHDD = cDrive.TotalFreeSpace / 1024 / 1024 / 1024;
                result.UsedHDD = (cDrive.TotalSize - cDrive.TotalFreeSpace) / 1024 / 1024 / 1024;
            }

            return result;
        }

        public static void Run()
        {
            Thread t = new Thread(delegate()
            {
                while (true)
                {
                    Thread.Sleep(HealthMonitor.Step);
                    Post(instance.GetHealthStatus());
                }
            }
            );

            t.Start();
        }

        private List<Tuple<DateTime, HealthStatusView>> history = new List<Tuple<DateTime, HealthStatusView>>();

        private static void Post(HealthStatusView status)
        {
            instance.history.Add(new Tuple<DateTime, HealthStatusView>(
                DateTime.UtcNow,
                status
            ));

            MosaicHub.PostHealthStatus(status);
        }

        public static List<Tuple<DateTime, AveragedHealthStatusView>> BySeconds()
        {
            var x = from h in instance.history
                    group h by new DateTime(
                        h.Item1.Year, h.Item1.Month, h.Item1.Day,
                        h.Item1.Hour, h.Item1.Minute, h.Item1.Second, DateTimeKind.Utc) into bySeconds
                    select new Tuple<DateTime, AveragedHealthStatusView>(
                        bySeconds.Key,
                        new AveragedHealthStatusView()
                        {
                            CpuUsage = bySeconds.Average(o => o.Item2.CpuUsage),
                            DiskUsage = bySeconds.Average(o => o.Item2.DiskUsage),
                            UsedRam = bySeconds.Average(o => o.Item2.UsedRam),
                            TotalRam = bySeconds.First().Item2.UsedRam + bySeconds.First().Item2.FreeRam
                        });

            return x.ToList();
        }

        public static List<Tuple<DateTime, HealthStatusView>> FullHistory
        {
            get
            {
                return instance.history;
            }
            private set { }
        }
    }
}